package com.easyworkflow.web.spring;

import com.auth.domain.T_user;
import com.auth.domain.T_user_role;
import com.auth.service.T_userService;
import com.auth.service.T_user_roleService;
import com.business.domain.*;
import com.business.service.*;
import com.common.db.JsonVO;
import com.common.db.Pg;
import com.common.utils.BeanUtils;
import com.common.utils.DateUtil;
import com.common.utils.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

//import com.workflow.WorkFlowUtils;
//import com.business.mapper.T_task_instanceMapper;

@Controller
public class WorkFlowController {
    private static Logger log = Logger.getLogger(WorkFlowController.class.getName());

    @Resource
    private T_taskService t_taskService;
    @Resource
    private T_task_nodeService t_task_nodeService;
    @Resource
    private T_task_instanceService t_task_instanceService;
    @Resource
    private T_task_node_instanceService t_task_node_instanceService;
    @Resource
    private T_userService t_userService;
    @Resource
    private T_user_roleService t_user_roleService;
    @Resource
    private T_newsService t_newsService;

    private Pg pg;

    /**
     * 注意：上线前需要在此配置：
     * 在系统运行前，配置好工作流程后，taskid固定下来后，在这里配置业务申请biztype值与taskid对应关系；
     *
     * @return
     */
    public Integer getTaskIdByBiztype(String types) {
        T_task task = new T_task();
        task.setExt1(types);
        task.setStartNo(0);
        task.setEndNo(1000);
        task.setPageSize(1000);
        List list = t_taskService.findAll(task);
        if(null!=list && list.size()>0){
            task = (T_task) list.get(0);
            return  task.getTaskid();
        }else{
            log.error("------没有找到流程关联字符串="+types+"的流程配置信息，请先配置该流程！------");
            //throw new Exception("工作流启动时，没有找到流程关联字符串="+types+"的流程配置信息，请先配置该流程！");
            //如果没有配置，默认全部走到 请假申请流程；
            return  -1;  //标准演示流程=14;
        }
    }

    /**
     * 注意：需要初始化；系统上线前，把待办任务审核页面进入的明细审核业务审核页面配置好；
     * 从待办任务页面点击审核按钮，跳转到不同业务详情的审核页面；
     * 所有的 审核页面 跳转全部放到这里；进行统一管理；
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/toShFactory")
    public String toShFactory(javax.servlet.http.HttpServletRequest request, HttpServletResponse response) {
        log.debug("------从待办任务页面点击审核按钮，跳转到不同业务详情的审核页面 start------");
        String returl ="";
        String biztype ="";
        String appid ="";

        if(null != request.getParameter("biztype")&&!"".equals(request.getParameter("biztype"))){
            biztype = request.getParameter("biztype");
            appid = request.getParameter("appid");
            if("qjsq".equals(biztype)){
                returl = "business/t_company/t_companyCurdSH";
            }else if("cwqk".equals(biztype)){
                // TODO: 2021/4/23
                returl = "business/t_company/t_demoCurdSH";
            }else{
                // TODO: 2021/4/23;  默认全部跳转到t_demoCurdSH.jsp 现实审核页面；
                returl = "business/t_demo/t_demoCurdSH";
            }
        }else {
            //如果没填biztype，也能走到默认测试工作流程进行测试；
            returl = "business/t_demo/t_demoCurdSH";
        }
        log.debug("------从待办任务页面点击审核按钮，跳转到不同业务详情的审核页面 end------biztype="+biztype+";returl="+returl);
        return returl;
    }

    /**
     * 1、启动工作流，返回成功或者失败信息json格式结果如：result:[success/error]
     * 业务申请页面点击“发起申请”按钮时，带参数流程id:taskid、业务申请id：appid；去后台查询该流程对应节点数据，
     * 找到第一个节点数据，插入流程实例表、流程节点实例表，生成第一岗待审批数据，即待办任务；
     * @todo 1、返回下一岗审核人员名单让当前提交页面知道找谁审批；2、页面提示改成不自动消失的；
     * @param taskid
     * @param appid
     * @param request
     * @return JsonVO
     */
    public JsonVO startMyTask(int taskid, String types, int appid, HttpServletRequest request) {
        JsonVO vo = new JsonVO();
        vo.setResult("error");
        vo.setJieguo(false);

        //1、检查：是否已经提交过申请；
        // 检查(appid+taskid)是否已经提交过的工作流审核申请信息，如果提交了返回失败及提示信息；
        T_task_node_instance t_task_node_instance = new T_task_node_instance();
        t_task_node_instance.setTaskid(taskid);
        t_task_node_instance.setAppid(appid);
        t_task_node_instance.setStartNo(0);
        t_task_node_instance.setPageSize(1000);
        t_task_node_instance.setEndNo(1000);
        List tinstanceList = t_task_node_instanceService.findAll(t_task_node_instance);
        if (null != tinstanceList && tinstanceList.size() > 0) {
            vo.setInfo("------startMyTask提示：taskid=" + taskid + "，appid=" + appid + "已经发起过申请，请勿重复提交!");
            log.error(vo.getInfo());
            return vo;
        }

        //2、检查：是否存在流程节点配置信息；
        // 如果不存在taskid对应的流程节点配置数据，返回错误信息；
        T_task_node t_task_node = new T_task_node();
        t_task_node.setTaskid(taskid);
        t_task_node.setStartNo(0);
        t_task_node.setPageSize(1000);
        t_task_node.setEndNo(1000);
        List t_task_nodeList = t_task_nodeService.findAll(t_task_node);
        if (null == t_task_nodeList || t_task_nodeList.size() == 0) {
            vo.setInfo("------startMyTask没有找到流程节点信息，请联系管理员先配置流程taskid=" + taskid + "对应流程节点数据！");
            log.error(vo.getInfo());
            return vo;
        }

        //3.1、检查第一岗节点数据；
        // 查询taskid对应流程第一岗数据，并插入流程实例、流程节点实例表生成流程数据；
        t_task_node = getFirstStepNode(t_task_nodeList);
        //如果查询到流程第一个节点信息，则插入待审核任务数据；
        if (null == t_task_node) {
            vo.setInfo("------startMyTask流程没有配置节点信息，请先配置taskid=" + taskid + "流程节点数据！");
            log.error(vo.getInfo());
            return vo;
        }
        //如果流程中该节点岗位设置为“是否上级审批=是：1”；则需要取 当前发起人对应部门的领导userid存储到该节点审批人字段；
        //if("1".equals(t_task_node.getExt4())){

        //3.2、检查第一岗节点审核人员数据；检查第一岗是否有审核人员；
        //领导审批： 上级审批=是：1;对应上级审批人
        //上级审批=是：1;对应上级审批人
        String parentuserid = "";
        if("1".equals(t_task_node.getExt4())){
            parentuserid = getParentUserid(request);
        }
        //角色审批人： 当前申请人的部门领导为空，则去找该岗（第一岗）是否设置了角色审批；
        String roleid = t_task_node.getRoleid();
        String roleuserid = getUseridByRoleid(roleid);
        //直接审核人：当前岗位审核人
        String curruserid = t_task_node.getUserid();
        String userid = parentuserid + roleuserid + curruserid;
        if( "".equals(userid) || null==userid ) {
            vo.setInfo("------startMyTask流程taskid=" + taskid + ",审核人userid="+userid+" 当前发起人所属部门没有配置部门领导、没有配置审核角色、没有配置审核人！请先配置发起人部门领导人或配置审核角色或配置审核人！");
            log.error(vo.getInfo());
            return vo;
        }

        //4、生成流程数据；
        // 插入下一岗流程实例；
        T_task_instance tinstance = new T_task_instance();
        tinstance.setTaskid(taskid);
        tinstance.setTaskname(t_task_node.getExt5()); //流程名称
        tinstance.setInstancestatus("0");
        tinstance.setCreater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        tinstance.setCreatertime(DateUtil.getCurrDateTimeStand());
        tinstance.setAppid(appid);
        tinstance.setBiztype(types);
        if (t_task_instanceService.save(tinstance) > 0) {

            //5、生成流程节点实例到数m据；
            // 即生成待办任务数据；流程节点实例数据加工
            T_task_node_instance tninstance = new T_task_node_instance();
            tninstance.setTaskid(taskid);
            tninstance.setNodeid(t_task_node.getNodeid());
            tninstance.setNodestep(t_task_node.getNodestep());
            tninstance.setFirststep(t_task_node.getExt5()); //流程名称
            tninstance.setLaststep(t_task_node.getNodename()); //节点名称
            tninstance.setTninstancestatus("0"); //有效
            tninstance.setCreater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
            tninstance.setCreatetime(DateUtil.getCurrDateTimeStand());
            tninstance.setInstanceid(tinstance.getInstanceid());
            tninstance.setAppid(appid);

            //2021-9-11 @auth davexin 直接把所有可以审批的：部门领导userid、审核角色对应审核人、直接审核人 合并后设置为审核人；
            tninstance.setUserid(StringUtils.removeSameString( userid ,","));
            tninstance.setRoleid(t_task_node.getRoleid());
            tninstance.setBiztype(types);
            t_task_node_instanceService.save(tninstance);
            vo.setResult("success");
            vo.setInfo("工作流启动成功！接下来审核人:"+tninstance.getUserid()+"！ taskid=" + taskid + ",appid=" + appid);
            vo.setJieguo(true);
            log.error("-----startMyTask 启动taskid=" + taskid + ",appid=" + appid + "工作流成功！");
            log.error(vo.getInfo());
        }

        return vo;
    }

    /**
     * 根据roleid返回对应 人员；
     * @param roleid  roleid = 物业经理(207),园区管理员(206),人事(204),
     * @return  彭丽丽(penglili),张霞(zhangxia),
     */
    private String getUseridByRoleid(String roleid){
        StringBuffer ret = new StringBuffer();
        if(null == roleid || "".equals(roleid) ) {
            return "";
        }else{
            String[] arryroleid = roleid.split(",");
            String objStr ="";
            for(int i=0;i<arryroleid.length;i++){
                String temp = arryroleid[i];
                //取双括号中 roleid；
                objStr = arryroleid[i].substring(arryroleid[i].indexOf("(")+1,arryroleid[i].indexOf(")"));
                //先去取出所有 rolid对应的userid；
                T_user_role user_role = new T_user_role();
                user_role.setRoleid(new Integer(objStr));
                user_role.setStartNo(0);
                user_role.setEndNo(1000);
                user_role.setPageSize(100);
                List listUserid = t_user_roleService.findAll(user_role);
                if(listUserid!=null){
                    Iterator it = listUserid.iterator();
                    while (it.hasNext()){
                        user_role = (T_user_role)it.next();
                        String userid= user_role.getUserid();
                        //取出所有userid对应的username；
                        if(!"".equals(userid)){
                            T_user user  = new T_user();
                            user.setUserid(userid);
                            user.setStartNo(0);
                            user.setEndNo(1000);
                            user.setPageSize(100);
                            List users = t_userService.findAll(user);
                            if(users!=null){
                                Iterator itusers = users.iterator();
                                while (itusers.hasNext()){
                                    user = (T_user)itusers.next();
                                    String username = user.getUsername();
                                    ret.append(username+"("+userid+"),");
                                }
                            }
                        }
                    } //end while;
                } //end userlist;
            } //end length;
            return ret.toString();
        } //end nullif
    }

    /* 正向流程，逆向流程（退回）不能使用该方法；
     * 获取当前用户部门的领导，设置工作下一岗为申请人领导审批；
     * brabnchid 与当前用户相同，ismanager=1，则认为是当前用户的部门领导；
     */
    private String getParentUserid( HttpServletRequest request){
        String cuurUseridParentid = "";
        String cuurUserBranchid = request.getSession().getAttribute("FREE_BRANCHID").toString();
        T_user t_user = new T_user();
        t_user.setBranchid(cuurUserBranchid);
        t_user.setIsmanager("1");
        t_user.setStartNo( 0 );
        t_user.setEndNo( 10000 );

        List list = t_userService.findAll(t_user);
        Iterator it = list.iterator();
        t_user =null;
        while (it!=null&&it.hasNext()){
            t_user = (T_user) it.next();
            //需要设置为：item.username(item.userid)形式；与设置节点审核人时一致，否则待办任务会找不到对应待审核任务数据：find_in_set ( 'test888;', c.USERID ), ；
            cuurUseridParentid += t_user.getUsername()+"("+t_user.getUserid()+"),";
        }
        return cuurUseridParentid;
    }

    /**
     * 2、审核通过，返回成功或者失败信息json格式结果如：result:[success/error]
     * 点击业务审核页面“审核通过”按钮时，提交参数taskNodeInstanceid流程节点实例id；
     * 去查询对应流程节点实例数据，并更新该条待办任务为已办理成功，
     * 判断是否是最有一岗，如果是最后一岗，则直接更新流程实例数据为已完成；
     * 如果不是最后一岗，则查询下一岗数据，插入流程节点实例表，即下一岗待办任务；
     *
     * @param taskNodeInstanceid
     * @param note
     * @param request
     * @return JsonVO
     */
    public JsonVO doMyAgree(int taskNodeInstanceid, String note, HttpServletRequest request) {
        JsonVO vo = new JsonVO();
        vo.setResult("error");
        vo.setJieguo(false);

        //加工流程节点信息查询对象
        T_task_node_instance t_task_node_instance = new T_task_node_instance();
        t_task_node_instance.setTninstanceid(taskNodeInstanceid);
        t_task_node_instance.setStartNo(0);
        t_task_node_instance.setPageSize(1000);
        t_task_node_instance.setEndNo(1000);

        //查询流程当前节点实例信息；
        t_task_node_instance = t_task_node_instanceService.findById(t_task_node_instance);
        if (null == t_task_node_instance) {
            vo.setInfo("------doMyAgree没有找到流程节点实例信息，流程节点实例数据Tninstanceid=" + t_task_node_instance.getTninstanceid() + "意外丢失！");
            log.error(vo.getInfo());
            return vo;
        }
        //更新时做幂等使用；同时根据 id + 状态；
        t_task_node_instance.setMemo3(t_task_node_instance.getTninstancestatus());

        //查询流程节点数据；
        T_task_node t_task_node = new T_task_node();
        t_task_node.setTaskid(t_task_node_instance.getTaskid());
        t_task_node.setStartNo(0);
        t_task_node.setPageSize(10000);
        t_task_node.setEndNo(10000);
        List list = t_task_nodeService.findAll(t_task_node);
        if (null == list || list.size() == 0) {
            vo.setInfo("------doMyAgree没有找到流程节点信息，流程节点数据taskid=" + t_task_node_instance.getTaskid() + "意外丢失,请确保没有删除该流程配置！");
            log.error(vo.getInfo());
            return vo;
        }

        //更新当前节点完成;
        t_task_node_instance.setTninstancestatus("1"); //完成
        t_task_node_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        t_task_node_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
        t_task_node_instance.setNote(note);
        if (t_task_node_instanceService.updateMD(t_task_node_instance) == 0) {
            vo.setInfo("------doMyAgree更新当前岗位审核通过失败，请确认该流程当前审核岗位对应流程节点实例Tninstanceid=" + t_task_node_instance.getTninstanceid() + "数据是否存在！");
            log.error(vo.getInfo());
            return vo;
        }

        //查询下一岗信息，如果有下一岗，则更新当前岗的审核通过，然后插入下一岗数据，即下一岗待办任务；
        T_task_node next_task_node = getNextStepNode(t_task_node_instance.getNodestep(), list);
        //没有下一岗数据，更新流程实例完成；
        if (null == next_task_node) {
            T_task_instance t_task_instance = new T_task_instance();
            t_task_instance.setInstanceid(t_task_node_instance.getInstanceid());
            t_task_instance = t_task_instanceService.findById(t_task_instance);
            t_task_instance.setInstancestatus("1");
            //幂等使用；
            t_task_instance.setMemo3(t_task_instance.getInstancestatus());
            t_task_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
            t_task_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
            if (t_task_instanceService.update(t_task_instance) == 0) {
                //if(t_task_instanceService.updateMD(t_task_instance)==0){
                vo.setInfo("------doMyAgree更新流程结束失败，请确认该流程实例数据Instanceid=" + t_task_instance.getInstanceid() + "是否存在！");
                return vo;
            }else{ //审核通过并且成功，流程结束；设置流程审核完成信息；
                vo.setInfo("最后一岗审核通过，流程结束！");
            }
        } else {//有下一岗数据，插入下一岗数据，即生成下一岗待办任务；
            T_task_node_instance next_node_instance = new T_task_node_instance();
            next_node_instance.setTninstancestatus("0");
            next_node_instance.setTaskid(next_task_node.getTaskid());
            next_node_instance.setNodeid(next_task_node.getNodeid());
            next_node_instance.setNodestep(next_task_node.getNodestep());
            next_node_instance.setFirststep(next_task_node.getExt5());
            next_node_instance.setLaststep(next_task_node.getNodename());

            //------------------------2021-9-11 @auth davexin start----------------------
            //检查第一岗节点审核人员数据；检查第一岗是否有审核人员；
            //上级审批=是：1;对应上级审批人
            String parentuserid = "";
            if("1".equals(next_task_node.getExt4())){
                parentuserid = getParentUserid(request);
            }
            //当前申请人的部门领导为空，则去找该岗（第一岗）是否设置了角色审批；
            String roleid = next_task_node.getRoleid();
            String roleuserid = getUseridByRoleid(roleid);
            //当前岗位审核人
            String curruserid = next_task_node.getUserid();
            String userid = parentuserid + roleuserid + curruserid;
            //如果 上级审批对应部门没有设置领导、岗位角色审批人没有设置角色、审批人没有设置人；
            //if( "".equals(parentuserid) && "".equals(userid) && "".equals(roleuserid)) {
            if( "".equals(userid) || null==userid ) {
                vo.setInfo("------doMyAgree 流程taskid=" + next_task_node.getTaskid() + ",审核人userid="+userid+" 当前发起人所属部门没有配置部门领导、没有配置审核角色、没有配置审核人！请先配置发起人部门领导人或配置审核角色或配置审核人！");
                log.error(vo.getInfo());
                return vo;
            }
            //2021-9-11 @auth davexin 直接把所有可以审批的：部门领导userid、审核角色对应审核人、直接审核人 合并后设置为审核人；
            next_node_instance.setUserid(StringUtils.removeSameString( userid ,","));
            //------------------------2021-9-11 @auth davexin end ----------------------

            next_node_instance.setRoleid(next_task_node.getRoleid());
            next_node_instance.setInstanceid(t_task_node_instance.getInstanceid());
            next_node_instance.setAppid(t_task_node_instance.getAppid());
            next_node_instance.setBiztype(t_task_node_instance.getBiztype());

            next_node_instance.setCreater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
            next_node_instance.setCreatetime(DateUtil.getCurrDateTimeStand());

            vo.setInfo("流程审核通过成功！接下来审核人:"+next_node_instance.getUserid()+"！ taskid=" + next_node_instance.getTaskid() + ",appid=" + next_node_instance.getAppid());

            if (t_task_node_instanceService.save(next_node_instance) == 0) {
                vo.setInfo("------doMyAgree生成下一岗待办任务失败，请确认下一岗流程节点数据Nodeid=" + next_node_instance.getNodeid() + "是否被删除！");
                return vo;
            }
        }

        log.error(vo.getInfo());

        vo.setResult("success");
        vo.setJieguo(true);
        return vo;
    }

    /**
     * 4、修改T_task_instance信息并且返回成功或者失败信息json格式结果如：result:[success/error]
     *
     * @param taskNodeInstanceid
     * @param note
     * @param request
     * @return JsonVO
     */
    public JsonVO doMyBack(int taskNodeInstanceid, String note, HttpServletRequest request) {
        JsonVO vo = new JsonVO();
        vo.setResult("error");
        vo.setJieguo(false);

        //加工流程节点信息查询对象
        T_task_node_instance t_task_node_instance = new T_task_node_instance();
        t_task_node_instance.setTninstanceid(taskNodeInstanceid);
        t_task_node_instance.setStartNo(0);
        t_task_node_instance.setPageSize(1000);
        t_task_node_instance.setEndNo(1000);

        //查询流程节点实例信息；
        t_task_node_instance = t_task_node_instanceService.findById(t_task_node_instance);
        if (null == t_task_node_instance) {
            vo.setInfo("------doMyBack没有找到流程节点实例信息，流程节点实例数据Tninstanceid=" + t_task_node_instance.getTninstanceid() + "意外丢失！");
            log.error(vo.getInfo());
            return vo;
        }
        //幂等使用
        t_task_node_instance.setMemo3(t_task_node_instance.getTninstancestatus());

        //查询流程节点数据；
        T_task_node t_task_node = new T_task_node();
        t_task_node.setTaskid(t_task_node_instance.getTaskid());
        t_task_node.setStartNo(0);
        t_task_node.setPageSize(10000);
        t_task_node.setEndNo(10000);
        List list = t_task_nodeService.findAll(t_task_node);
        if (null == list || list.size() == 0) {
            vo.setInfo("------doMyBack没有找到流程节点信息，流程节点数据Taskid=" + t_task_node.getTaskid() + "意外丢失,请确保没有删除该流程配置！");
            log.error(vo.getInfo());
            return vo;
        }

        //更新当前节点完成;
        t_task_node_instance.setTninstancestatus("2"); //完成,更新为退回；
        t_task_node_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        t_task_node_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
        t_task_node_instance.setNote(note);
        //if(t_task_node_instanceService.updateMD(t_task_node_instance)==0){
        if (t_task_node_instanceService.update(t_task_node_instance) == 0) {
            vo.setInfo("------doMyBack更新当天岗位审核通过失败，请确认该流程当前审核岗位对应流程节点实例数据Tninstanceid=" + t_task_node_instance.getTninstanceid() + "是否存在！");
            return vo;
        }

        //查询前一岗信息，如果有前一岗，则更新当前岗的审核通过，然后插入前一岗数据，即生成退回到前一岗待办任务；
        T_task_node pre_task_node = getPreStepNode(t_task_node_instance.getNodestep(), list);
        //没有前一岗数据，更新流程实例完成；即没有前一岗，退回前一岗时则强制结束流程，审核不通过；可在申请页面重新发起；
        if (null == pre_task_node) {
            T_task_instance t_task_instance = new T_task_instance();
            t_task_instance.setInstanceid(t_task_node_instance.getInstanceid());
            t_task_instance = t_task_instanceService.findById(t_task_instance);
            //幂等使用
            t_task_instance.setMemo3(t_task_instance.getInstancestatus());

            t_task_instance.setInstancestatus("2"); //退回，发起人可以重新提交，@todo doRestart方法待实现
            t_task_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
            t_task_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());

            vo.setInfo("工作流退回成功！退回到发起人，流程结束。流程状态=‘已退回’！ taskid=" + t_task_instance.getTaskid() + ",appid=" + t_task_instance.getAppid());

            if (t_task_instanceService.updateMD(t_task_instance) == 0) {
                vo.setInfo("------doMyBack更新流程退回失败，请确认该流程实例数据Instanceid=" + t_task_instance.getInstanceid() + "是否存在！");
                return vo;
            }
        } else {//有下一岗数据，插入下一岗数据，即生成下一岗待办任务；
            T_task_node_instance pre_node_instance = new T_task_node_instance();
            pre_node_instance.setTninstancestatus("0");
            pre_node_instance.setTaskid(pre_task_node.getTaskid());
            pre_node_instance.setNodeid(pre_task_node.getNodeid());
            pre_node_instance.setNodestep(pre_task_node.getNodestep());
            pre_node_instance.setInstanceid(t_task_node_instance.getInstanceid());
            pre_node_instance.setLaststep(pre_task_node.getNodename());
            pre_node_instance.setFirststep(pre_task_node.getExt5());

            //如果流程中该节点岗位设置为“是否上级审批=是：1”；流程只能在发起人对应下一岗设为部门领导审批；
            // 如果非第一岗，退回时找不到该设置为谁审批；
            // 则需要取 当前发起人对应部门的领导userid存储到该节点审批人字段；
            String parentuserid = "";
            if("1".equals(pre_task_node.getExt4())){ //否上级审批=是：1;
                //退回流程处理与正项流程不一样，需要先通过 pre_node_instance.appid 找到申请发起人的userid，
                // 然后找到该userid对应的部门领导userid， 设置下一岗审批人为找到的申请发起人部门领导userid；
                T_news news = new T_news();
                news.setId(t_task_node_instance.getAppid());
                news = t_newsService.findById(news);
                String branchid = news.getHticount(); //发起申请人对应部门id，也就是部门名称；目前id和名称一致；
                T_user user = new T_user();
                user.setBranchid(branchid); //部门id相同；
                user.setIsmanager("1"); //并且是部门领导；
                user.setStartNo(0);
                user.setEndNo(1000);
                user.setPageSize(1000);
                List userlist = t_userService.findAll(user);
                if (userlist!=null && userlist.size()>0) {
                    //设置流程节点审批人
                    //需要设置为：item.username(item.userid)形式；与设置节点审核人时一致，否则待办任务会找不到对应待审核任务数据：find_in_set ( 'test888;', c.USERID ), ；
                    user = (T_user)userlist.get(0); //取第一个取到的领导userid作为退回下一岗的审批人；
                    parentuserid = user.getUsername() +"("+user.getUserid()+")," ;   //正向用：getParentUserid(request);
                }
            }
            //当前申请人的部门领导为空，则去找该岗（第一岗）是否设置了角色审批；
            String roleid = pre_task_node.getRoleid();
            String roleuserid = getUseridByRoleid(roleid);
            //当前岗位审核人
            String curruserid = pre_task_node.getUserid();
            String userid = parentuserid + roleuserid + curruserid;
            //如果 上级审批对应部门没有设置领导、岗位角色审批人没有设置角色、审批人没有设置人；
            //if( "".equals(parentuserid) && "".equals(userid) && "".equals(roleuserid)) {
            if( "".equals(userid) || null==userid ) {
                vo.setInfo("------doMyBack流程退回失败,流程taskid=" + pre_task_node.getTaskid() + ",审核人userid="+userid+" 流程发起人所属部门没有配置部门领导、没有配置审核角色、没有配置审核人！请先配置发起人部门领导人或配置审核角色或配置审核人！");
                log.error(vo.getInfo());
                return vo;
            }

            //2021-9-11 @auth davexin 直接把所有可以审批的：部门领导userid、审核角色对应审核人、直接审核人 合并后设置为审核人；
            pre_node_instance.setUserid(StringUtils.removeSameString( userid ,","));

            pre_node_instance.setRoleid(pre_task_node.getRoleid());
            pre_node_instance.setAppid(t_task_node_instance.getAppid());
            pre_node_instance.setInstanceid(t_task_node_instance.getInstanceid());
            pre_node_instance.setBiztype(t_task_node_instance.getBiztype());

            pre_node_instance.setCreater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
            pre_node_instance.setCreatetime(DateUtil.getCurrDateTimeStand());
            vo.setInfo("工作流退回成功！接下来审核人:"+pre_node_instance.getUserid()+"！ taskid=" + pre_node_instance.getTaskid() + ",appid=" + pre_node_instance.getAppid());
            if (t_task_node_instanceService.save(pre_node_instance) == 0) {
                vo.setInfo("------doMyBack流程退回失败，生成前一岗待办任务失败，请确认前一岗流程节点Nodeid=" + pre_node_instance.getNodeid() + "是否被删除！");
                return vo;
            }
        }

        log.error(vo.getInfo());
        vo.setResult("success");
        vo.setJieguo(true);
        return vo;
    }

    /**
     * 4.x、修改T_task_instance信息并且返回成功或者失败信息json格式结果如：result:[success/error]
     *
     * @param taskNodeInstanceid
     * @param note
     * @param request
     * @return JsonVO
     */
    public JsonVO doMyBackToCreater(int taskNodeInstanceid, String note, HttpServletRequest request) {
        JsonVO vo = new JsonVO();
        vo.setResult("error");
        vo.setJieguo(false);

        //加工流程节点信息查询对象
        T_task_node_instance t_task_node_instance = new T_task_node_instance();
        t_task_node_instance.setTninstanceid(taskNodeInstanceid);
        t_task_node_instance.setStartNo(0);
        t_task_node_instance.setPageSize(1000);
        t_task_node_instance.setEndNo(1000);

        //查询流程节点实例信息；
        t_task_node_instance = t_task_node_instanceService.findById(t_task_node_instance);
        if (null == t_task_node_instance) {
            vo.setInfo("------doMyBack没有找到流程节点实例信息，流程节点实例数据Tninstanceid=" + t_task_node_instance.getTninstanceid() + "意外丢失！");
            log.error(vo.getInfo());
            return vo;
        }
        //幂等使用
        t_task_node_instance.setMemo3(t_task_node_instance.getTninstancestatus());

        //查询流程节点数据；
        T_task_node t_task_node = new T_task_node();
        t_task_node.setTaskid(t_task_node_instance.getTaskid());
        t_task_node.setStartNo(0);
        t_task_node.setPageSize(10000);
        t_task_node.setEndNo(10000);
        List list = t_task_nodeService.findAll(t_task_node);
        if (null == list || list.size() == 0) {
            vo.setInfo("------doMyBack没有找到流程节点信息，流程节点数据Taskid=" + t_task_node.getTaskid() + "意外丢失,请确保没有删除该流程配置！");
            log.error(vo.getInfo());
            return vo;
        }

        //更新当前节点完成;
        t_task_node_instance.setTninstancestatus("3"); //完成并退回至发人,更新为退回；  0-草稿，1-审核通过；2-审核退回；3-审核退回至发起人；
        t_task_node_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        t_task_node_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
        t_task_node_instance.setNote(note);
        //if(t_task_node_instanceService.updateMD(t_task_node_instance)==0){
        if (t_task_node_instanceService.update(t_task_node_instance) == 0) {
            vo.setInfo("------doMyBack更新当天岗位审核退回至发起人失败，请确认该流程当前审核岗位对应流程节点实例数据Tninstanceid=" + t_task_node_instance.getTninstanceid() + "是否存在！");
            return vo;
        }

        //退回至发起人并结束流程，更新流程实例完成；
        T_task_instance t_task_instance = new T_task_instance();
        t_task_instance.setInstanceid(t_task_node_instance.getInstanceid());
        t_task_instance = t_task_instanceService.findById(t_task_instance);
        t_task_instance.setInstancestatus("3"); //1：流程结束；3：退回至发起人并结束流程；
        //幂等使用；
        t_task_instance.setMemo3(t_task_instance.getInstancestatus());
        t_task_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        t_task_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
        if (t_task_instanceService.update(t_task_instance) == 0) {
            //if(t_task_instanceService.updateMD(t_task_instance)==0){
            vo.setInfo("------doMyAgree更新流程退回至发起人 并更新流程结束失败，请确认该流程实例数据Instanceid=" + t_task_instance.getInstanceid() + "是否存在！");
            return vo;
        }else{ //审核通过并且成功，流程结束；设置流程审核完成信息；
            vo.setInfo("最后一岗审核通过，流程结束！");
        }

        log.error(vo.getInfo());
        vo.setResult("success");
        vo.setJieguo(true);
        return vo;
    }


    /**
     * 5、修改T_task_instance信息并且返回成功或者失败信息json格式结果如：result:[success/error]
     *
     * @param t_task_instance
     * @param request
     * @return JsonVO
     */
    public JsonVO doMyReStart(T_task_instance t_task_instance, HttpServletRequest request) {
        JsonVO vo = new JsonVO();
        vo.setResult("error");
        vo.setJieguo(false);
        //如果有特殊值需要处理，在此处手工转换
        //T_task_instance t_task_instanceTemp = t_task_instanceService.findById(t_task_instance);
        //t_task_instanceTemp.setXXX(t_task_instance.getXXX());
        //if(t_task_instanceService.update(t_task_instanceTemp)){

        if (t_task_instanceService.update(t_task_instance) > 0) {
            vo.setResult("success");
            vo.setJieguo(true);
        }
        return vo;
    }

    /**
     * 更新当前节点已经完成，当前节点实例设置为不通过，整个实例设置为强制结束；instances=2，tninstances=1；
     * 修改T_task_instance信息tninstances=2；
     * 修改T_task_node_instance信息instances=1并且 note 自动加上文案： 提前结束流程；
     * 并且返回成功或者失败信息json格式结果如：result:[success/error]
     *
     * @param taskNodeInstanceid
     * @param note
     * @param request
     * @return JsonVO
     */
    public JsonVO doMyFinish(int taskNodeInstanceid, String note, HttpServletRequest request) {
        JsonVO vo = new JsonVO();
        vo.setResult("error");
        vo.setJieguo(false);

        //加工流程节点信息查询对象
        T_task_node_instance t_task_node_instance = new T_task_node_instance();
        t_task_node_instance.setTninstanceid(taskNodeInstanceid);
        t_task_node_instance.setStartNo(0);
        t_task_node_instance.setPageSize(1000);
        t_task_node_instance.setEndNo(1000);

        //查询流程当前节点实例信息；
        t_task_node_instance = t_task_node_instanceService.findById(t_task_node_instance);
        if (null == t_task_node_instance) {
            vo.setInfo("------doMyAgree没有找到流程节点实例信息，流程节点实例数据Tninstanceid=" + t_task_node_instance.getTninstanceid() + "意外丢失！");
            log.error(vo.getInfo());
            return vo;
        }

        //更新当前节点完成;
        //更新时做幂等使用；同时根据 id+ 状态；
        t_task_node_instance.setMemo3(t_task_node_instance.getTninstancestatus());
        t_task_node_instance.setTninstancestatus("1"); //完成
        t_task_node_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        t_task_node_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
        t_task_node_instance.setNote(note + "<br>注意：该岗位审核结束流程");
        if (t_task_node_instanceService.updateMD(t_task_node_instance) == 0) {
            vo.setInfo("------doMyAgree更新当前岗位审核通过,结束流程失败，请确认该流程当前审核岗位对应流程节点实例Tninstanceid=" + t_task_node_instance.getTninstanceid() + "数据是否存在！");
            log.error(vo.getInfo());
            return vo;
        }

        //更新流程实例（正常）结束；只是在note里面加上文案：注意：该岗位审核强制结束流程；
        T_task_instance t_task_instance = new T_task_instance();
        t_task_instance.setInstanceid(t_task_node_instance.getInstanceid());
        t_task_instance = t_task_instanceService.findById(t_task_instance);
        t_task_instance.setInstancestatus("2"); //强制结束流程，结果不通过
        //幂等使用；
        t_task_instance.setMemo3(t_task_instance.getInstancestatus());
        t_task_instance.setUpdater(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
        t_task_instance.setUpdatetime(DateUtil.getCurrDateTimeStand());
        if (t_task_instanceService.update(t_task_instance) == 0) {
            //if(t_task_instanceService.updateMD(t_task_instance)==0){
            vo.setInfo("------doMyAgree更新流程结束失败，请确认该流程实例数据Instanceid=" + t_task_instance.getInstanceid() + "是否存在！");
            return vo;
        }

        vo.setResult("success");
        vo.setJieguo(true);
        return vo;
    }

    /**
     * 获取流程第一个节点数据,也就是step最小的流程节点；
     */
    private T_task_node getFirstStepNode(List taskNodeList) {
        T_task_node t_task_node = null;
        T_task_node tempNode = null;
        int firstStep = 100000;
        int tempNodeStep;
        //假设第一步node值很大，所有该流程节点的step值与该值比较，比该值小则把该值赋予最小节点，比较完成后最小的则认为是第一个节点；
        if (null != taskNodeList && taskNodeList.size() > 0) {
            Iterator it = taskNodeList.iterator();
            while (it.hasNext()) {
                tempNode = (T_task_node) it.next();
                tempNodeStep = tempNode.getNodestep();
                if (tempNodeStep <= firstStep) {
                    firstStep = tempNodeStep;
                    t_task_node = tempNode;
                }
            }
        }

        return t_task_node;
    }

    /**
     * 获取流程当前节点前一个节点数据,也就是step的前一步，退回上一岗操作；
     * Java中sort实现降序排序
     * 利用Collections的reverseOrder方法：
     */
    private T_task_node getPreStepNode(int step, List taskNodeList) {
        T_task_node t_task_node = null;
        T_task_node tempNode = null;
        Integer[] arr;
        //假设第一步node值很大，所有该流程节点的step值与该值比较，比该值小则把该值赋予最小节点，比较完成后最小的则认为是第一个节点；
        if (null != taskNodeList && taskNodeList.size() > 0) {
            arr = new Integer[taskNodeList.size()];
            int i = 0;
            Map map = new HashMap();
            Iterator it = taskNodeList.iterator();
            while (it.hasNext()) {
                tempNode = (T_task_node) it.next();
                arr[i] = tempNode.getNodestep();
                map.put(tempNode.getNodestep(), tempNode);
                i++;
            }
            //倒序排列数组；
            Arrays.sort(arr, Collections.reverseOrder());
            //倒序比较该流程所有节点对应审批step执行顺序；如果比当前的节点step值小，即是前一节点step；
            for (int n = 0; n < arr.length; n++) {
                if (arr[n] < step) { //倒序排列节点，最大的节点排在最前面，第一个比当前step小的就是要找的退回目标节点；
                    t_task_node = (T_task_node) map.get(arr[n]);
                    log.error("------查询退回到上一节点信息，======退回到第[" + arr[n] + "]=" + arr[n] + " 节点！======");
                    return t_task_node;
                }
            }
        }

        return t_task_node;
    }

    /**
     * 获取流程当前节点前一个节点数据,也就是step的的第一步，退回第一岗操作；
     * Java中sort实现降序排序
     * 利用Collections的reverseOrder方法：取最后一个就是最小的，也就是第一个；
     */
    private T_task_node getFirstStepNode(int step, List taskNodeList) {
        T_task_node t_task_node = null;
        T_task_node tempNode = null;
        Integer[] arr;
        //假设第一步node值很大，所有该流程节点的step值与该值比较，比该值小则把该值赋予最小节点，比较完成后最小的则认为是第一个节点；
        if (null != taskNodeList && taskNodeList.size() > 0) {
            arr = new Integer[taskNodeList.size()];
            int i = 0;
            Map map = new HashMap();
            Iterator it = taskNodeList.iterator();
            while (it.hasNext()) {
                tempNode = (T_task_node) it.next();
                arr[i] = tempNode.getNodestep();
                map.put(tempNode.getNodestep(), tempNode);
                i++;
            }
            //倒序排列数组；
            Arrays.sort(arr, Collections.reverseOrder());
            //倒序比较该流程所有节点对应审批step执行顺序；如果比当前的节点step值小，即是前一节点step；
            for (int n = 0; n < arr.length; n++) {
                if (arr[n] < step) { //倒序排列节点，最大的节点排在最前面，第一个比当前step小的就是要找的退回目标节点；
                    t_task_node = (T_task_node) map.get(arr[n]);
                    log.error("------查询退回到上一节点信息，======退回到第[" + arr[n] + "]=" + arr[n] + " 节点！======");
                    //return t_task_node; 这是返回前一岗；
                }
            }
        }
        return t_task_node;
    }

    /**
     * 获取流程下一个节点数据;
     * 把当前节点setp作为比较值，然后按照从小到大排序，第一个就是下一节点；
     */
    private T_task_node getNextStepNode(int step, List taskNodeList) {
        T_task_node nextTaskNode = null;
        T_task_node tempNode = null;
        TreeMap map = new TreeMap();
        int tempNodeStep;
        //假设第一步node值很大，所有该流程节点的step值与该值比较，比该值小则把该值赋予最小节点，比较完成后最小的则认为是第一个节点；
        if (null != taskNodeList && taskNodeList.size() > 0) {
            Iterator it = taskNodeList.iterator();
            while (it.hasNext()) {
                tempNode = (T_task_node) it.next();
                tempNodeStep = tempNode.getNodestep();
                map.put(tempNodeStep, tempNode);
            }

            //treemap根据key排序,默认是按升序排序；
            Set<String> keySet = map.keySet();
            Iterator iter = keySet.iterator();
            int key;
            while (iter.hasNext()) {
                key = new Integer(iter.next().toString()).intValue();
                System.out.println("@@@@@@@@@@@@@@@@@@@@ key:value=" + key + ":" + map.get(key));
                //按照节点step步骤从小到大排列，当前step=参数传入值 并且 还有下一个步骤（如果没有下一个步骤，则返回空，说明是最后一岗了，即最后一个审批节点）；
                if (key == step && iter.hasNext()) {
                    //取treemap中顺序的下一个step对应 节点对象，即为当前节点下一个节点数据；
                    nextTaskNode = (T_task_node) map.get(new Integer(iter.next().toString()).intValue());
                    return nextTaskNode;
                }
            }
        }

        return null;
    }

    /**
     * 1、获取 待办任务列表
     *
     * @param request
     * @return Pg，json格式
     */
    public Pg getMyList(HttpServletRequest request) {
        int pageSize = 10;
        int startIndex = 0;
        T_task_node_instance t_task_node_intance = new T_task_node_instance();
        try {
            if (request.getParameter("pageSize") != null) {
                pageSize = BeanUtils.stringToInt("pageSizeFlag", request.getParameter("pageSize"));
            }
            if (request.getParameter("startIndex") != null) {
                startIndex = BeanUtils.stringToInt("startIndexFlag", request.getParameter("startIndex"));
            }
            if (request.getParameter("instanceid") != null && !"".equals(request.getParameter("instanceid"))) {
                t_task_node_intance.setInstanceid(new Integer(request.getParameter("instanceid")));
            }
            if (request.getParameter("appid") != null && !"".equals(request.getParameter("appid"))) {
                t_task_node_intance.setAppid(new Integer(request.getParameter("appid")));
            }
            if (request.getParameter("startdate") != null && !"".equals(request.getParameter("startdate"))) {
                t_task_node_intance.setStartdate(request.getParameter("startdate"));
            }
            if (request.getParameter("enddate") != null && !"".equals(request.getParameter("enddate"))) {
                t_task_node_intance.setEnddate(request.getParameter("enddate"));
            }
            if (request.getParameter("firststep") != null && !"".equals(request.getParameter("firststep"))) {
                t_task_node_intance.setFirststep(request.getParameter("firststep"));
            }
            if (request.getParameter("laststep") != null && !"".equals(request.getParameter("laststep"))) {
                t_task_node_intance.setLaststep(request.getParameter("laststep"));
            }
            if (request.getParameter("creater") != null && !"".equals(request.getParameter("creater"))) {
                t_task_node_intance.setCreater(request.getParameter("creater"));
            }
            if (request.getParameter("tninstancestatus") != null && !"".equals(request.getParameter("tninstancestatus"))) {
                t_task_node_intance.setTninstancestatus(request.getParameter("tninstancestatus"));
            }
            if (request.getParameter("tninstanceid") != null && !"".equals(request.getParameter("tninstanceid"))) {
                t_task_node_intance.setTninstanceid(new Integer(request.getParameter("tninstanceid")) );
            }

            t_task_node_intance.setStartNo(startIndex);
            t_task_node_intance.setPageSize(pageSize);
            t_task_node_intance.setEndNo(pageSize);
            //待办任务中存储的userid格式：”李青(liqing),zhangsan(zhangsan),“；需要加工成如上格式数据，才能查询到数据；
            t_task_node_intance.setUserid(request.getSession().getAttribute("username").toString() + "(" + request.getSession().getAttribute("userid").toString() + ")");
            //t_task_node_intance.setRoleid("");
            List<T_task_node_instance> findAll = t_task_node_instanceService.findAll(t_task_node_intance);
            int totalCount = t_task_node_instanceService.findCountAll(t_task_node_intance);
            pg = new Pg(findAll, totalCount, pageSize, startIndex);
            request.setAttribute("t_task_node_instanceList", findAll);
            request.setAttribute("pg", pg);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("------query t_task_node_instanceService List error:" + e);
        }

        return pg;
    }

    /**
     * 根据instanceid获取 该任务所有审核意见列表；
     *
     * @param request
     * @return Pg，json格式
     */
    public Pg getMyNoteList(HttpServletRequest request) {
        int pageSize = 10;
        int startIndex = 0;
        T_task_node_instance t_task_node_intance = new T_task_node_instance();
        try {
            if (request.getParameter("pageSize") != null) {
                pageSize = BeanUtils.stringToInt("pageSizeFlag", request.getParameter("pageSize"));
            }
            if (request.getParameter("startIndex") != null) {
                startIndex = BeanUtils.stringToInt("startIndexFlag", request.getParameter("startIndex"));
            }
            if (request.getParameter("instanceid") != null && !"".equals(request.getParameter("instanceid"))) {
                t_task_node_intance.setInstanceid(new Integer(request.getParameter("instanceid")));
            }
            if (request.getParameter("appid") != null && !"".equals(request.getParameter("appid"))) {
                t_task_node_intance.setAppid(new Integer(request.getParameter("appid")));
            }
            if (request.getParameter("startdate") != null && !"".equals(request.getParameter("startdate"))) {
                t_task_node_intance.setStartdate(request.getParameter("startdate"));
            }
            if (request.getParameter("enddate") != null && !"".equals(request.getParameter("enddate"))) {
                t_task_node_intance.setEnddate(request.getParameter("enddate"));
            }
            if (request.getParameter("firststep") != null && !"".equals(request.getParameter("firststep"))) {
                t_task_node_intance.setFirststep(request.getParameter("firststep"));
            }
            if (request.getParameter("laststep") != null && !"".equals(request.getParameter("laststep"))) {
                t_task_node_intance.setLaststep(request.getParameter("laststep"));
            }
            if (request.getParameter("creater") != null && !"".equals(request.getParameter("creater"))) {
                t_task_node_intance.setCreater(request.getParameter("creater"));
            }
            if (request.getParameter("tninstancestatus") != null && !"".equals(request.getParameter("tninstancestatus"))) {
                t_task_node_intance.setTninstancestatus(request.getParameter("tninstancestatus"));
            }

            t_task_node_intance.setStartNo(startIndex);
            t_task_node_intance.setPageSize(pageSize);
            t_task_node_intance.setEndNo(pageSize);
            //待办任务中存储的userid格式：”李青(liqing),zhangsan(zhangsan),“；需要加工成如上格式数据，才能查询到数据；
            // 不能限制是本人的，该任务所有审核节点的审核意见都要显示给当前审核人；
            // t_task_node_intance.setUserid(request.getSession().getAttribute("username").toString()+"("+request.getSession().getAttribute("userid").toString()+")");
            //t_task_node_intance.setRoleid("");
            List<T_task_node_instance> findAll = t_task_node_instanceService.findAll(t_task_node_intance);
            int totalCount = t_task_node_instanceService.findCountAll(t_task_node_intance);
            pg = new Pg(findAll, totalCount, pageSize, startIndex);
            request.setAttribute("t_task_node_instanceList", findAll);
            request.setAttribute("pg", pg);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("------query t_task_node_instanceService List error:" + e);
        }

        return pg;
    }
}









